package com.gzc.just.play.last.war.common.service;

import com.gzc.just.play.last.war.common.distributed.ServiceInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Server registry service
 * Manages server registration information and status
 */
@Service
public class ServerRegistryService {
    
    private static final Logger log = LoggerFactory.getLogger(ServerRegistryService.class);
    
    // Server registration information
    private final ConcurrentHashMap<String, ServerInfo> serverRegistry = new ConcurrentHashMap<>();
    
    // Server load information
    private final ConcurrentHashMap<String, LoadInfo> serverLoadInfo = new ConcurrentHashMap<>();
    
    /**
     * Register server
     * @param serverInfo Server information
     * @return Whether registration succeeded
     */
    public boolean registerServer(ServerInfo serverInfo) {
        String serverId = serverInfo.getServerId();
        
        // Check if already registered
        if (serverRegistry.containsKey(serverId)) {
            log.warn("Server {} is already registered", serverId);
            return false;
        }
        
        // Register server
        serverRegistry.put(serverId, serverInfo);
        serverLoadInfo.put(serverId, new LoadInfo());
        
        log.info("Registered server: {} at {}:{}", 
                 serverId, serverInfo.getHost(), serverInfo.getPort());
        return true;
    }
    
    /**
     * Unregister server
     * @param serverId Server ID
     * @return Whether unregistration succeeded
     */
    public boolean unregisterServer(String serverId) {
        if (serverRegistry.remove(serverId) != null) {
            serverLoadInfo.remove(serverId);
            
            log.info("Unregistered server: {}", serverId);
            return true;
        }
        
        log.warn("Server {} is not registered", serverId);
        return false;
    }
    
    /**
     * Get server information
     * @param serverId Server ID
     * @return Server information
     */
    public ServerInfo getServerInfo(String serverId) {
        return serverRegistry.get(serverId);
    }
    
    /**
     * Get all server information
     * @return All server information
     */
    public Map<String, ServerInfo> getAllServerInfo() {
        return Map.copyOf(serverRegistry);
    }
    
    /**
     * Get all server instances
     * @param serviceName Service name
     * @return All server instances
     */
    public List<ServiceInstance> getInstances(String serviceName) {
        return serverRegistry.values().stream()
                .filter(info -> serviceName.equals(info.getServiceName()))
                .map(info -> {
                    ServiceInstance instance = new ServiceInstance();
                    instance.setInstanceId(info.getServerId());
                    instance.setServiceName(info.getServiceName());
                    instance.setHost(info.getHost());
                    instance.setPort(info.getPort());
                    return instance;
                })
                .toList();
    }
    
    /**
     * Get server status
     * @param serverId Server ID
     * @return Server status
     */
    public boolean isServerActive(String serverId) {
        return serverRegistry.containsKey(serverId);
    }
    
    /**
     * Update server load information
     * @param serverId Server ID
     * @param loadInfo Load information
     */
    public void updateServerLoad(String serverId, LoadInfo loadInfo) {
        serverLoadInfo.put(serverId, loadInfo);
    }
    
    /**
     * Get server load information
     * @param serverId Server ID
     * @return Load information
     */
    public LoadInfo getServerLoad(String serverId) {
        return serverLoadInfo.get(serverId);
    }
    
    /**
     * Get all server load information
     * @return All server load information
     */
    public Map<String, LoadInfo> getAllServerLoad() {
        return Map.copyOf(serverLoadInfo);
    }
    
    /**
     * Server information class
     */
    public static class ServerInfo {
        private String serverId;
        private String serviceName;
        private String host;
        private int port;
        
        public ServerInfo() {
        }
        
        public ServerInfo(String serverId, String serviceName, String host, int port) {
            this.serverId = serverId;
            this.serviceName = serviceName;
            this.host = host;
            this.port = port;
        }
        
        public String getServerId() {
            return serverId;
        }
        
        public void setServerId(String serverId) {
            this.serverId = serverId;
        }
        
        public String getServiceName() {
            return serviceName;
        }
        
        public void setServiceName(String serviceName) {
            this.serviceName = serviceName;
        }
        
        public String getHost() {
            return host;
        }
        
        public void setHost(String host) {
            this.host = host;
        }
        
        public int getPort() {
            return port;
        }
        
        public void setPort(int port) {
            this.port = port;
        }
    }
    
    /**
     * Load information class
     */
    public static class LoadInfo {
        private long lastUpdateTime;
        private double cpuUsage;
        private double memoryUsage;
        private int activeConnections;
        private int requestCount;
        
        public LoadInfo() {
            this.lastUpdateTime = System.currentTimeMillis();
            this.cpuUsage = 0.0;
            this.memoryUsage = 0.0;
            this.activeConnections = 0;
            this.requestCount = 0;
        }
        
        public long getLastUpdateTime() {
            return lastUpdateTime;
        }
        
        public void setLastUpdateTime(long lastUpdateTime) {
            this.lastUpdateTime = lastUpdateTime;
        }
        
        public double getCpuUsage() {
            return cpuUsage;
        }
        
        public void setCpuUsage(double cpuUsage) {
            this.cpuUsage = cpuUsage;
        }
        
        public double getMemoryUsage() {
            return memoryUsage;
        }
        
        public void setMemoryUsage(double memoryUsage) {
            this.memoryUsage = memoryUsage;
        }
        
        public int getActiveConnections() {
            return activeConnections;
        }
        
        public void setActiveConnections(int activeConnections) {
            this.activeConnections = activeConnections;
        }
        
        public int getRequestCount() {
            return requestCount;
        }
        
        public void setRequestCount(int requestCount) {
            this.requestCount = requestCount;
        }
    }
}